package com.tz.shop.seckill.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.tz.shop.common.config.RabbitService;
import com.tz.shop.model.activity.SeckillGoods;
import com.tz.shop.seckill.mapper.SeckillGoodsMapper;
import com.tz.shop.seckill.mapper.SeckillMapper;
import com.tz.shop.seckill.mapper.SeckillOrderMapper;
import com.tz.shop.seckill.pojo.SeckillOrder;
import com.tz.shop.seckill.pojo.UserRecode;
import com.tz.shop.seckill.service.SeckillService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author 铁铸
 * @create 2021-07-16 20:37
 */
@Service
public class SeckillServiceImpl implements SeckillService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SeckillMapper seckillMapper;

    @Autowired
    private RabbitService rabbitService;

    /**
     * 秒杀商品列表
     *
     * @param time
     * @return
     */
    @Override
    public List<SeckillGoods> getSeckillGoods(String time) {
        List<SeckillGoods> list = redisTemplate.boundHashOps("SeckillGoods_" + time).values();
        return list;
    }

    /**
     * 秒杀商品详情
     *
     * @param time
     * @param id
     * @return
     */
    @Override
    public SeckillGoods getSeckillGood(String time, String id) {
        SeckillGoods listById = (SeckillGoods)redisTemplate.boundHashOps("SeckillGoods_" + time).get(id);
        return listById;
    }


    /**
     * 下单
     * 通过时间time从redis中查出商品，skuId找到商品，username表示是哪个用户
     *
     * @param time
     * @param skuId
     * @param userName
     * @return
     */
    @Override
    public UserRecode addOrder(String time, String skuId, String userName) {
        //获取商品的详细信息,从redis中获取
        SeckillGoods goodsList = (SeckillGoods) redisTemplate.boundHashOps("SeckillGoods_" + time).get(skuId);
        //记录用户的排队信息
        UserRecode userRecode = new UserRecode();
        //防止用户重复排队-------todo
        //用redis的增加方法，每次自增1来做判断。大于1就需要改变排队状态
        Long increment = redisTemplate.boundValueOps("SeckillUserQueue_" + userName)
                        .increment(1);
        if (increment>1){
            userRecode.setStatus(3);
            userRecode.setMsg("重复排队");
            return userRecode;
        }
        userRecode.setUsername(userName);  //记录用户的编号用来标识用户的唯一标识。
        userRecode.setCreateTime(new Date());  //得有用户创建时间
        //状态为排队中
        userRecode.setStatus(1); //给定排队的状态
        userRecode.setGoodsId(skuId); //对应的商品编号
        userRecode.setTime(time); //给的一个时间值
        userRecode.setNum(1);  //假设购买一个商品
        //将用户排队信息存入到redis中去,用boundValueOps直接set就好了
        redisTemplate.boundValueOps("SeckillStatus_"  + userName).set(userRecode);
        //发送消息进行异步下单
        rabbitService.sendMessage("seckill_exchange",
                "seckill.order.add",
                JSONObject.toJSONString(userRecode));
        //返回用户排队的结果
        return userRecode;
    }

    /**
     * 查询用户排队的信息
     *
     * @param userNmae
     * @return
     */
    @Override
    public UserRecode getUserRecode(String userNmae) {
        return (UserRecode)redisTemplate.boundValueOps("SeckillStatus_" + userNmae).get();
    }

    /**
     * 查询秒杀订单的详情
     *
     * @param username
     * @param orderId
     * @return
     */
    @Override
    public List<SeckillOrder> getSeckillOrderList(String username, String orderId) {
        if (StringUtils.isEmpty(orderId)){
            //查询所有秒杀订单的列表
            return redisTemplate.boundHashOps("SeckillOrder_"+username).values();
        }else {
            //获取某一个商品详情
            List<SeckillOrder> seckillOrders=new ArrayList<>();
            SeckillOrder seckillOrder = (SeckillOrder) redisTemplate.boundHashOps("SeckillOrder_" + username).get(orderId);
            seckillOrders.add(seckillOrder);
            return seckillOrders;
        }
    }

    @Autowired
    private SeckillOrderMapper seckillOrderMapper;

    /**
     * 支付成功
     *
     * @param map
     */
    @Override
    public void paySuccess(Map<String, String> map) {
        //先获取微信的附加参数
        String attach = map.get("attach");
        //若为空则获取支付宝的附加参数
        if(StringUtils.isEmpty(attach)){
            attach = map.get("passback_params");
        }
        //类型转换
        Map<String,String> attachMap = JSONObject.parseObject(attach, Map.class);
        String username = attachMap.get("username");
        String outTradeNo = map.get("out_trade_no");
        //从redis中获取订单的信息
        SeckillOrder seckillOrder =
                (SeckillOrder)redisTemplate.boundHashOps("SeckillOrder_" + username).get(outTradeNo);
        //判断前置状态
        if(seckillOrder != null && seckillOrder.getStatus().equals("0")){
            //修改订单的支付状态
            seckillOrder.setStatus("2");
            //修改redis中订单的状态
            redisTemplate.boundHashOps("SeckillOrder_" + username).put(outTradeNo, seckillOrder);
            //将订单的信息存入数据库
            seckillOrderMapper.insert(seckillOrder);
            //库存回滚---1.redis回滚  2.数据库回滚
            UserRecode userRecode = (UserRecode)redisTemplate.boundValueOps("SeckillStatus_" + username).get();
            rollBackSeckillGoodsNum(userRecode.getGoodsId(), userRecode.getTime(), userRecode.getNum());
            //排队标识删除掉
            redisTemplate.delete("SeckillUserQueue_" + username);
            //排队状态可以删掉了
            redisTemplate.delete("SeckillStatus_" + username);

        }
    }

    /**
     * 支付失败
     *
     * @param map
     */
    @Override
    public void payFail(Map<String, String> map) {
        //先获取微信的附加参数
        String attach = map.get("attach");
        //若为空则获取支付宝的附加参数
        if(StringUtils.isEmpty(attach)){
            attach = map.get("passback_params");
        }
        //类型转换，对应附加参数
        Map<String,String> attachMap = JSONObject.parseObject(attach, Map.class);
        String username = attachMap.get("username");
        String outTradeNo = map.get("out_trade_no");
        //从redis中获取订单的信息
        SeckillOrder seckillOrder =
                (SeckillOrder)redisTemplate.boundHashOps("SeckillOrder_" + username).get(outTradeNo);
        //判断前置状态
        if(seckillOrder != null && seckillOrder.getStatus().equals("0")){
            //修改订单的支付状态
            seckillOrder.setStatus("2");
            //修改redis中订单的状态
            redisTemplate.boundHashOps("SeckillOrder_" + username).put(outTradeNo, seckillOrder);
            //将订单的信息存入数据库
            seckillOrderMapper.insert(seckillOrder);
            //库存回滚---1.redis回滚  2.数据库回滚
            UserRecode userRecode = (UserRecode)redisTemplate.boundValueOps("SeckillStatus_" + username).get();
            rollBackSeckillGoodsNum(userRecode.getGoodsId(), userRecode.getTime(), userRecode.getNum());
            //排队标识删除掉
            redisTemplate.delete("SeckillUserQueue_" + username);
            //排队状态可以删掉了
            redisTemplate.delete("SeckillStatus_" + username);

        }
    }


    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    /**
     * 回滚秒杀商品的库存
     */
    private void rollBackSeckillGoodsNum(String skuId, String time, Integer num){
        //从redis中获取商品的数据
        SeckillGoods seckillGoods =
                (SeckillGoods)redisTemplate.boundHashOps("SeckillGoods_" + time).get(skuId);
        if(seckillGoods == null){
            //商品已经售罄了--更新数据库中的库存数据
            seckillGoodsMapper.updateSeckillGoodsStock(skuId, num);
        }else{
            //redis中还有数据--更新redis中的库存数据
            String[] seckillGoodsQueue = getSeckillGoodsQueue(skuId, num);
            redisTemplate.boundListOps("seckillGoodsQueue_" + skuId).leftPushAll(seckillGoodsQueue);
            //回滚库存的对象
            redisTemplate.boundHashOps("SeckillGoodsStockNum").increment(skuId, num);
        }
    }

    /**
     * 构建商品库存个数长度的数组
     * @param goodsId
     * @param stockCount
     * @return
     */
    private String[] getSeckillGoodsQueue(String goodsId, Integer stockCount){
        //构建一个库存长度的数组
        String[] ids = new String[stockCount];
        //元素填充
        for (int i = 0; i < stockCount; i++) {
            ids[i] = goodsId;
        }
        //返回数据
        return ids;
    }
}
